﻿using System;
using System.Collections.ObjectModel;
using System.Text;
using System.IO;
using MUD.Network;
using MUD.Lib.Objects;
using MUD.Lib.Objects.Users;
using MUD.Lib.Utils;
using MUD.Lib.Daemons;
using MUD.Lib.Objects.Domains;
using System.Threading;
using MUD.Lib.Objects.Rooms;


namespace MUD.Lib
{
    /// <summary>
    /// This class is the core of the mudlib, handling interfacing with the underlying socket server,
    /// starting and managing all daemons and managing the world object graph.
    /// </summary>
    public class Master
    {
        private SocketServer Server;
        private UserCollection Users = new UserCollection();

        public event EventHandler<MUD.Network.LogEventArgs> OnLog;
        public event EventHandler<ShutdownEventArgs> OnShutdown;

        public delegate void HeartbeatHandler(double elapsed);
        public event HeartbeatHandler OnHeartbeat;
        private DateTime LastHeartbeat;
        public double HeartbeatInterval;
        private System.Timers.Timer HeartbeatTimer;

        internal DomainController DC = new DomainController();

        internal Room StartRoom
        {
            get
            {
                return DC.Domains[0].Start;
            }
        }

        public Master(SocketServer server)
        {
            Server = server;
        }

        public void Initialize()
        {
            Log("*** Initializing Mud Master Object ***");
            Server.OnReceive += new EventHandler<ReceiveEventArgs>(Server_OnReceive);
            Server.OnConnectionStateChange += new EventHandler<ConnectionEventArgs>(Server_OnConnectionStateChange);
            CommandHook.Initialize();
            Log("Command Hook initialized with " + CommandHook.NumOfCommands + " commands found.");

            // Start the heartbeat
            LastHeartbeat = DateTime.Now;
            HeartbeatTimer = new System.Timers.Timer();
            HeartbeatTimer.AutoReset = true;
            HeartbeatTimer.Interval = HeartbeatInterval;
            HeartbeatTimer.Elapsed += new System.Timers.ElapsedEventHandler(DoHeartbeat);
            HeartbeatTimer.Start();

            // Start up the domain controller and initialize all rooms
            DC.Initialize();
            foreach (Domain domain in DC.Domains)
            {
                Log(domain.RoomCount + " rooms loaded in the " + domain.DomainName + " domain.");
            }

            MUD.Lib.Log.MasterObj = this;
        }

        void DoHeartbeat(object sender, System.Timers.ElapsedEventArgs e)
        {
            TimeSpan elapsed = e.SignalTime - LastHeartbeat;
            LastHeartbeat = e.SignalTime;
            //Log("Heartbeat pulsed: " + elapsed.TotalMilliseconds + " milliseconds.\r\n");
            if (OnHeartbeat != null)
                OnHeartbeat(elapsed.TotalMilliseconds);
        }

        void Server_OnConnectionStateChange(object sender, ConnectionEventArgs e)
        {
            switch (e.Event)
            {
                case ConnectionEventType.Connected:
                    UserConnected(e.Client);
                    break;
                case ConnectionEventType.Disconnected:
                    UserDisconnected(e.Client);
                    break;
            }
        }

        private void UserDisconnected(AsyncClient asyncClient)
        {
            // TODO: if we're echoing all disconnect messages, do it here.
            // TODO: Clean up character references, remove the character from the world with a valid message
            Users.Remove(Users[asyncClient]);
        }

        internal void DisconnectUser(User user)
        {
            // Tell the server to disconnect this user and then handle the UserDisconnected event.
            Server.CloseConnection(user.Client.RecieveArgs);
        }

        private void UserConnected(AsyncClient asyncClient)
        {
            User newUser = new User(asyncClient, this);
            Users.Add(newUser);
            new Login(newUser);
            newUser.Write(File.ReadAllText(@"Resources/Greeting.txt"));
            newUser.PrintPrompt();
        }

        void Server_OnReceive(object sender, ReceiveEventArgs e)
        {
            Users[e.Client].Recieve(e.Message);
        }

        public void Log(string message)
        {
            if (OnLog != null)
                OnLog(this, new LogEventArgs(message));
        }

        public void Start()
        {

        }

        public void Shutdown(string Username, string reason)
        {
            if (OnShutdown != null)
            {
                OnShutdown(null, new ShutdownEventArgs(Username, reason));
            }
        }

        public void Broadcast(string Username, string message)
        {
            foreach (User user in Users)
            {
                user.Write(String.Format(Strings.Broadcast, Username, message));
            }
        }

       

    }
}
